package com.lsj.spring.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author Lsj
 * @version 1.0
 * @date 2021/6/24 18:39
 * aspect切面声明,标注在类,接口或者是枚举上
 * component表示一个带注释的类是一个足尖,成为spring管路的bean
 */
@Aspect
@Component
public class LogAspect {
    /**
     * 声明切点,定义拦截规则,确定那些方法会被切入
     */
    @Pointcut("@annotation(com.lsj.spring.anno.Save)")
    public void insert(){

    }

    /**
     * joinPoint对象封装了springAop中切面方法的信息
     * 在切面方法中加入joinPoint参数就可以获得封装该方法信息的joinPoint对象
     * @param joinPoint 切面方法
     */
    @Before("insert()")
    public void before(JoinPoint joinPoint){
        // 通过joinPoint来拿到方法调用信息
        Object[] objs = joinPoint.getArgs();
        for (Object obj:
             objs) {
            // 设置createBy
            try{
                // 通过该实例的getClass方法获得class对象
                Class<? extends Object> clazz = obj.getClass();
                // 返回此对象所表示的类或者是接口的public的field(属性)
                Field field = clazz.getField("createBy");
                // 返回此对象所表示的类或者接口的全部方法,getType表示得到的filed的属性类型
                Method setCreateBy = clazz.getMethod("setCreateBy",field.getType());
                // 方法参数化
                setCreateBy.invoke(obj,"lsj");
            }catch (NoSuchFieldException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e){
                e.printStackTrace();
            }
        }
        System.out.println("切面的前置操作");
    }

    @After("insert()")
    public void after(){
        System.out.println("后置操作日志");
    }

    /**
     * 环绕切面
     * @param pjp joinPoint的增强方法
     * @return 返回值
     * @throws Throwable 异常
     */
    @Around("insert()")
    public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
        // 环绕可以和before或者是after一起使用
        System.out.println("环绕中");
        Object res = pjp.proceed();
        System.out.println("环绕中");
        return res;
    }

    @AfterThrowing("insert()")
    public void error(JoinPoint joinPoint){
        System.out.println("报错了,大兄弟");
    }
}
